import { ImplementsInterface } from "../../../Decorator/Decorator";
import { List } from "../../../Support/Share/Lib/Collections/List";
import { Queue } from "../../../Support/Share/Lib/Collections/Queue";
import { ISingletonUpdate } from "../../Singleton/ISingletonUpdate";
import { Singleton } from "../../Singleton/Singleton";
import { Log } from "../Log/Log";
import { CoroutineLock } from "./CoroutineLock";
import { CoroutineLockQueueType } from "./CoroutineLockQueueType";
import { CoroutineLockType } from "./CoroutineLockType";

interface FrameRunData {
    coroutineLockType: number;
    key: number;
    level: number;
}

@ImplementsInterface(ISingletonUpdate)
export class CoroutineLockComponent extends Singleton<CoroutineLockComponent> implements ISingletonUpdate {

    private static _Instance: CoroutineLockComponent;
    static get Instance() {
        return this._Instance;
    }

    protected set Instance(value: CoroutineLockComponent) {
        CoroutineLockComponent._Instance = value;
    }

    private readonly list: List<CoroutineLockQueueType> = new List<CoroutineLockQueueType>();
    private readonly nextFrameRun: Queue<FrameRunData> = new Queue<FrameRunData>();

    constructor() {
        super();
        for (let i = 0; i < CoroutineLockType.Max; ++i) {
            let coroutineLockQueueType = new CoroutineLockQueueType(i);
            this.list.Add(coroutineLockQueueType);
        }
    }

    public override  Dispose(): void {
        this.list.Clear();
        this.nextFrameRun.Clear();
    }

    public Update(): void {
        // 循环过程中会有对象继续加入队列
        while (this.nextFrameRun.Count > 0) {
            let { coroutineLockType, key, level } = this.nextFrameRun.Dequeue();
            this.Notify(coroutineLockType, key, level);
        }
    }

    public RunNextCoroutine(coroutineLockType: number, key: number, level: number) {
        // 一个协程队列一帧处理超过100个,说明比较多了,打个warning,检查一下是否够正常
        if (level == 100) {
            Log.Warning(`too much coroutine level: ${coroutineLockType} ${key}`);
        }

        this.nextFrameRun.Enqueue({ coroutineLockType, key, level });
    }

    public async Wait(coroutineLockType: number, key: number, time: number = 60000): Promise<CoroutineLock> {
        let coroutineLockQueueType = this.list.Get(coroutineLockType);
        return await coroutineLockQueueType.Wait(key, time);
    }

    private Notify(coroutineLockType: number, key: number, level: number): void {
        let coroutineLockQueueType = this.list.Get(coroutineLockType);
        coroutineLockQueueType.Notify(key, level);
    }

}